import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.File;
import java.sql.*;
import java.util.*;

public class CodeGenerator {
    public static void main(String[] args) {
        // 数据库配置
        String url = "jdbc:mysql://localhost:3308/coding_pai_learning?useSSL=false&serverTimezone=UTC";
        String username = "root";
        String password = "1234";

        // 项目路径
        String projectPath = System.getProperty("user.dir");

        // 获取数据库所有表名
        List<String> allTables = getAllTables(url, username, password);
        if (allTables.isEmpty()) {
            System.out.println("数据库中没有表或连接失败");
            return;
        }

        // 显示数据库名称
        String dbName = extractDatabaseName(url);
        System.out.println("数据库: " + (dbName != null ? dbName : "未知") + " 中的表：");
        System.out.println(String.join(", ", allTables));

        // 获取用户输入的表名
        Scanner scanner = new Scanner(System.in);
        System.out.print("\n请输入要生成的表名（多个用逗号分隔，支持通配符*）：");
        String tableInput = scanner.nextLine().trim();

        // 处理用户输入
        List<String> selectedTables;
        if (tableInput.equalsIgnoreCase("all") || tableInput.equals("*")) {
            selectedTables = allTables; // 生成所有表
        } else {
            selectedTables = new ArrayList<>();
            // 处理通配符和多个表名
            for (String tableName : tableInput.split(",")) {
                String trimmedName = tableName.trim();
                if (trimmedName.contains("*")) {
                    // 处理通配符
                    String pattern = trimmedName.replace("*", ".*");
                    for (String table : allTables) {
                        if (table.matches(pattern)) {
                            selectedTables.add(table);
                        }
                    }
                } else {
                    // 直接添加表名
                    if (allTables.contains(trimmedName)) {
                        selectedTables.add(trimmedName);
                    } else {
                        System.out.println("警告: 表 '" + trimmedName + "' 不存在");
                    }
                }
            }
        }

        if (selectedTables.isEmpty()) {
            System.out.println("没有有效的表名，程序退出");
            return;
        }

        System.out.println("将生成以下表: " + String.join(", ", selectedTables));


        // 路径配置
        Map<OutputFile, String> pathInfo = new HashMap<>();
        pathInfo.put(OutputFile.entity, projectPath + "/src/main/java/com/learning_paicoding/entity");
        pathInfo.put(OutputFile.mapper, projectPath + "/src/main/java/com/learning_paicoding/mapper");
        pathInfo.put(OutputFile.xml, projectPath + "/src/main/resources/mappers");
        pathInfo.put(OutputFile.service, projectPath + "/src/main/java/com/learning_paicoding/service");
        pathInfo.put(OutputFile.serviceImpl, projectPath + "/src/main/java/com/learning_paicoding/service/impl");
        pathInfo.put(OutputFile.controller, projectPath + "/src/main/java/com/learning_paicoding/controller");

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> {
                    builder.author("hph") // 作者名
                            .enableSwagger() // 开启 swagger 注解
//                          .enableFileOverride() // 开启文件覆盖（关键配置，全局覆盖）
                            .outputDir(projectPath + "/src/main/java")  // 输出目录
                            .disableOpenDir();
                })
                .packageConfig(builder -> {
                    builder.parent("") // 父包设为空
                            .pathInfo(pathInfo); // 使用自定义路径映射
                })

//                .packageConfig(builder -> {
//                    builder.parent("com.learning_paicoding") // 父包名
//                            .moduleName("entity") // 模块名
//                            .pathInfo(Collections.singletonMap(
//                                    OutputFile.xml,
//                                    projectPath + "/src/main/resources/mappers")); // XML位置
//                })
                .strategyConfig(builder -> {
                    builder.addInclude(selectedTables) // 要生成的表名
                            .addTablePrefix("t_", "sys_") // 过滤表前缀
                            .entityBuilder().enableFileOverride() // 实体配置，分层覆盖
                            .enableLombok() // 使用Lombok
                            .enableChainModel() // 启用链式模型
                            .enableTableFieldAnnotation() // 字段注解
                            .controllerBuilder() // 控制器配置
                            .enableRestStyle() // REST风格
                            .mapperBuilder() // 添加Mapper配置
                            .enableBaseResultMap() // 生成ResultMap
                            .enableBaseColumnList() // 生成基础列名
                            .serviceBuilder() // 添加Service配置
                            .formatServiceFileName("%sService") // 服务接口名
                            .formatServiceImplFileName("%sServiceImpl"); // 服务实现类名
                })
                .templateConfig(builder -> {
                    // 使用自定义实体类模板
                    builder.entity("/templates/tempfile_1751809468947");

                    // 禁用默认的controller/service/mapper模板（可选）
                    builder.disable(TemplateType.CONTROLLER);
                    builder.disable(TemplateType.SERVICE);
                    builder.disable(TemplateType.SERVICE_IMPL);
                    builder.disable(TemplateType.MAPPER);
                    builder.disable(TemplateType.XML);
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 模板引擎
                .execute();
        // 验证文件生成结果
        verifyFileGeneration(selectedTables, pathInfo, projectPath);

        // 计算并显示总耗时
        long endTime = System.currentTimeMillis();
        System.out.printf("代码生成完成！总耗时: %.2f 秒%n", (endTime - startTime) / 1000.0);

    }


    // 验证文件生成结果
    private static void verifyFileGeneration(List<String> tables,
                                             Map<OutputFile, String> pathInfo,
                                             String projectPath) {
        System.out.println("\n===== 文件生成验证 =====");

        // 创建结果汇总表
        List<Object[]> results = new ArrayList<>();
        int totalSuccess = 0;
        int totalFail = 0;

        // 实体类验证
        String entityPath = pathInfo.get(OutputFile.entity);
        int[] entityCounts = verifyFiles(tables, entityPath, "实体类", ".java");
        results.add(new Object[]{"实体类", entityCounts[0], entityCounts[1]});
        totalSuccess += entityCounts[0];
        totalFail += entityCounts[1];

        // Mapper接口验证
        String mapperPath = pathInfo.get(OutputFile.mapper);
        int[] mapperCounts = verifyFiles(tables, mapperPath, "Mapper接口", "Mapper.java");
        results.add(new Object[]{"Mapper接口", mapperCounts[0], mapperCounts[1]});
        totalSuccess += mapperCounts[0];
        totalFail += mapperCounts[1];

        // XML文件验证
        String xmlPath = pathInfo.get(OutputFile.xml);
        int[] xmlCounts = verifyFiles(tables, xmlPath, "Mapper XML", "Mapper.xml");
        results.add(new Object[]{"Mapper XML", xmlCounts[0], xmlCounts[1]});
        totalSuccess += xmlCounts[0];
        totalFail += xmlCounts[1];

        // Service接口验证
        String servicePath = pathInfo.get(OutputFile.service);
        int[] serviceCounts = verifyFiles(tables, servicePath, "Service接口", "Service.java");
        results.add(new Object[]{"Service接口", serviceCounts[0], serviceCounts[1]});
        totalSuccess += serviceCounts[0];
        totalFail += serviceCounts[1];

        // Service实现类验证
        String serviceImplPath = pathInfo.get(OutputFile.serviceImpl);
        int[] serviceImplCounts = verifyFiles(tables, serviceImplPath, "Service实现类", "ServiceImpl.java");
        results.add(new Object[]{"Service实现类", serviceImplCounts[0], serviceImplCounts[1]});
        totalSuccess += serviceImplCounts[0];
        totalFail += serviceImplCounts[1];

        // Controller验证
        String controllerPath = pathInfo.get(OutputFile.controller);
        int[] controllerCounts = verifyFiles(tables, controllerPath, "Controller", "Controller.java");
        results.add(new Object[]{"Controller", controllerCounts[0], controllerCounts[1]});
        totalSuccess += controllerCounts[0];
        totalFail += controllerCounts[1];
        // 计算成功率
        double totalFiles = totalSuccess + totalFail;
        double successRate = totalFiles > 0 ? (double) totalSuccess / totalFiles * 100 : 0;
        // 输出结果汇总表
        System.out.println("\n===== 生成结果汇总 =====");
        System.out.println("--------------------------------------------");
        System.out.printf("| 总计 | 成功数：%d | 失败数：%d | 成功率：%.2f%% | \n", totalSuccess, totalFail, successRate);
        System.out.println("--------------------------------------------");
    }


    // 验证特定类型的文件（返回成功和失败计数）
    private static int[] verifyFiles(List<String> tables,
                                     String basePath,
                                     String fileType,
                                     String fileSuffix) {
        int successCount = 0;
        int failCount = 0;

        if (basePath == null || basePath.isEmpty()) {
            System.out.println("跳过 " + fileType + " 验证: 路径未配置");
            return new int[]{0, 0};
        }

        File dir = new File(basePath);
        if (!dir.exists() || !dir.isDirectory()) {
            System.out.println("⚠️ " + fileType + " 目录不存在: " + basePath);
            return new int[]{0, 0};
        }

        System.out.println("\n验证 " + fileType + " (" + basePath + "):");

        for (String table : tables) {
            // 将表名转换为大驼峰格式（如 user_info -> UserInfo）
            String className = convertToCamelCase(table);

            // 构建预期文件名
            String expectedFileName = className + fileSuffix;
            File file = new File(dir, expectedFileName);

            if (file.exists()) {
                System.out.println("✅ " + className + fileSuffix + " 生成成功");
                successCount++;
            } else {
                System.out.println("❌ " + className + fileSuffix + " 生成失败");
                failCount++;
            }
        }

        System.out.printf("-- 生成结果: %d 成功, %d 失败%n", successCount, failCount);
        return new int[]{successCount, failCount};
    }

    // 将表名转换为大驼峰格式
    private static String convertToCamelCase(String tableName) {
        // 移除表前缀（如 t_、sys_）
        String name = tableName.replaceFirst("^(t_|sys_)", "");

        // 分割单词（下划线分隔）
        String[] parts = name.split("_");

        // 转换为大驼峰
        StringBuilder result = new StringBuilder();
        for (String part : parts) {
            if (!part.isEmpty()) {
                result.append(Character.toUpperCase(part.charAt(0)))
                        .append(part.substring(1).toLowerCase());
            }
        }

        return result.toString();
    }

    // 获取指定数据库的所有表名
    private static List<String> getAllTables(String url, String username, String password) {
        List<String> tables = new ArrayList<>();
        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            // 获取数据库名称（从连接URL中提取）
            String dbName = extractDatabaseName(url);
            // 获取数据库元数据
            DatabaseMetaData meta = conn.getMetaData();
            // 只查询当前数据库的表
            ResultSet rs = meta.getTables(dbName, null, "%", new String[]{"TABLE"});
            while (rs.next()) {
                tables.add(rs.getString("TABLE_NAME"));
            }
        } catch (SQLException e) {
            System.err.println("获取数据库表失败: " + e.getMessage());
        }
        return tables;
    }

    // 从JDBC URL中提取数据库名称
    private static String extractDatabaseName(String url) {
        // 示例URL: jdbc:mysql://localhost:3308/coding_pai_learning?useSSL=false&serverTimezone=UTC
        String[] parts = url.split("/");
        if (parts.length > 3) {
            String dbPart = parts[3];
            // 去除查询参数
            int paramIndex = dbPart.indexOf('?');
            if (paramIndex > 0) {
                return dbPart.substring(0, paramIndex);
            }
            return dbPart;
        }
        return null; // 无法解析时返回null
    }

}
